<template>
  <div class="area-page">
    <div class="canvas-wrap">
      <img ref="imageRef" class="img" :src="url" alt="" />
      <canvas
        id="canvas"
        ref="canvasRef"
        class="canvas-dom"
        :width="canvasInfo.width"
        :height="canvasInfo.height"
        @click="handleCanvasClick"
      ></canvas>
    </div>
    <div class="options-wrap">
      <div class="enable-wrap">
        启用禁用
        <t-switch v-model="optionsData.enable" class="common-switch" size="large" :label="['ON', 'OFF']"></t-switch>
      </div>
      <div class="enable-wrap">
        是否感兴趣
        <t-switch
          v-model="optionsData.isInterest"
          class="common-switch"
          size="large"
          :label="['ON', 'OFF']"
          @change="setCanvasData"
        ></t-switch>
      </div>
      <div class="tip">请开始绘制您感兴趣的区域</div>
      <div class="btn-wrap">
        <t-button
          variant="outline"
          :disabled="!(optionsData.status === 1 && optionsData.enable)"
          class="common-button"
          @click="beginDraw"
        >
          <template #icon><svg-icon class="icon" name="roi-begin"></svg-icon></template>
          开始绘制
        </t-button>
        <t-button
          variant="outline"
          class="common-button"
          :disabled="!(optionsData.status === 2 && optionsData.enable)"
          @click="endDraw"
        >
          <template #icon><svg-icon class="icon" name="roi-end"></svg-icon></template>
          停止绘制
        </t-button>
        <t-button variant="outline" class="common-button" :disabled="!optionsData.enable" @click="resetDraw">
          <template #icon><svg-icon class="icon" name="roi-reset"></svg-icon></template>
          重置绘制
        </t-button>
        <t-button variant="outline" class="common-button" :disabled="!optionsData.enable" @click="clearDraw">
          <template #icon><svg-icon class="icon" name="roi-clear"></svg-icon></template>
          清除绘制
        </t-button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import _ from 'lodash';
import { MessagePlugin } from 'tdesign-vue-next';
import { nextTick, ref, watch } from 'vue';

import { Point, Points, useCanvas } from '@/hooks/useCanvas';
import { getImageInfo } from '@/utils';

const props = defineProps({
  url: {
    type: String,
    default: '',
  },
  isInterest: {
    type: Boolean,
    default: true,
  },
  list: {
    type: Array as any,
    default: () => {
      return [];
    },
  },
});

const {
  initCanvas,
  renderRect,
  renderPolygon,
  setGlobalCompositeOperation,
  clearCanvasRect,
  isIntersect,
  renderPoint,
  renderLine,
  drawCtxBgColor,
  hollowOutRect,
} = useCanvas();

let ctx: CanvasRenderingContext2D = null;

const canvasRef = ref<HTMLCanvasElement>();
const imageRef = ref<HTMLImageElement>();
const canvasInfo = ref<any>({ width: 0, height: 379 });
const optionsData = ref({
  isInterest: true, // 是否感兴趣
  enable: true, // 是否开启
  status: 1, // 1 未绘制 2 绘制中 3 已绘制
});
let canvasDataList: Point[] = [];
let saveCanvasDataList: Point[] = [];

// 画点
const handleCanvasClick = (e: any) => {
  // 如果状态未启用或者状态不为绘制中，则不允许绘制
  if (!optionsData.value.enable || optionsData.value.status !== 2) return;
  const { offsetX, offsetY } = e;
  const targetData = { x: offsetX, y: offsetY };
  // 先判断该点连线与其他线段是否相交，不相交才往下走
  if (isIntersect(targetData, canvasDataList)) {
    MessagePlugin.error('线段相交');
    return;
  }
  canvasDataList.push(targetData);

  // 画点
  canvasDataList.forEach((item) => renderPoint(ctx, item));

  // 画线
  if (canvasDataList.length > 1) {
    const arr = canvasDataList.slice(-2) as Points;
    renderLine(ctx, arr);
  }
};

// 开始绘制
const beginDraw = () => {
  optionsData.value.status = 2;
};

// 结束绘制
const endDraw = async () => {
  if (canvasDataList.length < 3) {
    await MessagePlugin.error('请绘制');
    return;
  }

  // 先判断列表最后一个点与第一点连线与其他线段是否相交，不相交才绘制
  const targetData = canvasDataList[0];
  if (isIntersect(targetData, canvasDataList)) {
    await MessagePlugin.error('线段相交');
    return;
  }

  // 重绘canvas
  await setCanvasData();

  optionsData.value.status = 3;
};

// 清空画布
const clearCanvas = () => {
  clearCanvasRect(ctx, { x: 0, y: 0, w: canvasInfo.value.width, h: canvasInfo.value.height });

  if (!optionsData.value.isInterest) {
    // 重置区域为默认状态 - 非镂空
    setGlobalCompositeOperation(ctx);
    // 非感兴趣区域，画框处填充颜色
    renderRect(ctx, { x: 0, y: 0, w: canvasInfo.value.width, h: canvasInfo.value?.height });
  }
};

// 设置画布
const setCanvasData = async () => {
  clearCanvas();

  // 重置区域为默认状态 - 非镂空
  setGlobalCompositeOperation(ctx);

  if (optionsData.value.isInterest) {
    // 画点
    canvasDataList.forEach((item) => renderPoint(ctx, item));
    // 画多边形
    renderPolygon(ctx, canvasDataList);
    // 绘制多边形背景颜色
    drawCtxBgColor(ctx);
  } else {
    // 非感兴趣区域，画框处填充颜色
    renderRect(ctx, { x: 0, y: 0, w: canvasInfo.value.width, h: canvasInfo.value?.height });

    // 画点
    canvasDataList.forEach((item) => renderPoint(ctx, item));
    // 画多边形
    renderPolygon(ctx, canvasDataList);
    // 镂空多边形背景颜色
    hollowOutRect(ctx);
  }
};

const resetDraw = () => {
  clearCanvas();
  canvasDataList = _.cloneDeep(saveCanvasDataList);
  setCanvasData();
  optionsData.value.status = 3;
};

const clearDraw = () => {
  clearCanvas();
  optionsData.value.status = 1;
  canvasDataList = [];
};

const initData = () => {
  ctx = initCanvas('canvas');
  setCanvasData();
};

watch(
  () => props.url,
  async (url) => {
    const image = await getImageInfo(url);
    if (image) {
      const { width, height } = image;
      canvasInfo.value.width = (width * canvasInfo.value.height) / height;
    }
    await nextTick();
    optionsData.value.isInterest = props.isInterest;
    initData();
  },
  { immediate: true },
);

watch(
  () => props.list,
  async (list) => {
    if (!list.length) {
      optionsData.value.status = 1;
    } else {
      optionsData.value.status = 3;
      canvasDataList = _.cloneDeep(list);
      saveCanvasDataList = _.cloneDeep(list);
    }
  },
  { immediate: true },
);
</script>

<style lang="less" scoped>
.area-page {
  display: flex;
  gap: 16px;

  .canvas-wrap {
    height: 379px;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 5px 14px 0 rgb(0 0 0 / 10%);
    position: relative;

    .img {
      height: 100%;
    }

    .canvas-dom {
      position: absolute;
      left: 0;
      top: 0;
    }
  }

  .options-wrap {
    width: 181px;
    height: 374px;
    background: #f5f8ff;
    padding: 16px;
    box-sizing: border-box;
    box-shadow: 0 5px 14px 0 rgb(0 0 0 / 10%);

    .enable-wrap {
      color: #333;
      font-size: 12px;
      display: flex;
      align-items: center;
      gap: 14px;
      margin-bottom: 10px;
    }

    .tip {
      font-size: 12px;
      line-height: 14px;
      color: #666;
      margin: 11px 0 22px;
    }

    .btn-wrap {
      display: flex;
      gap: 22px;
      flex-direction: column;
      justify-content: center;
    }
  }

  .icon {
    color: #666;
    margin-right: 4px;
  }
}
</style>
